#include "can_drv.h"
#include "processor.h"
#include "int.h"
#include <xmc_gpio.h>
#include "../xmc4500/io.h"
#include "../canid/canid.h"


#define CAN_MIN_BAUD  CAN_10KBAUD
#define CIA_CAN_BIT_SAMPLE (int) (0.875 * 16)

#define TRAC_NODE_ID 0x701

// Panel Commands f?r den Panel Controller
#define fca_PANEL_NO_OP                0   ///< No Operation
#define fca_PANEL_INIT_LIST            1   ///< Initialize Lists
#define fca_PANEL_STAT_ALLOC_MSG       2   ///< Static Allocate
#define fca_PANEL_DYN_ALLOC_MSG        3   ///< Dynamic Allocate
#define fca_PANEL_STAT_INSERT_BEFORE   4   ///< Static Insert Before
#define fca_PANEL_DYN_INSERT_BEFORE    5   ///< Dynamic Insert Before
#define fca_PANEL_STAT_INSERT_BEHIND   6   ///< Static Insert Behind
#define fca_PANEL_DYN_INSERT_BEHIND    7   ///< Dynamic Insert Behind

#define CAN_FREQUENCY                  120000000L

#define CAN_EXT_RX_PIN                 P2_6   /*P2_6 CAN1*/
#define CAN_EXT_TX_PIN                 P2_7   /*P2_7 CAN1*/

#define CAN_INT_RX_PIN                 P1_5   /*CAN0*/
#define CAN_INT_TX_PIN                 P1_4   /*CAN0*/


/*===========================================================================
   local variable                                                        */

s16 can_baud_rate;
s16 can_sample_point;
s16 can_sjw;
s16 TSeg1;
s16 TSeg2;
s16 SJW;

s16 can_message_received;           /* CAN Message buffer has received data*/
s16 CAN_Error_Count_Transmit;
s16 CAN_Error_Count_Receive;
s16 CAN_Error_LEC;
s16 mailbox_assigned[NO_OF_CAN_MAILBOXES];

volatile s8 can_port_ext_transmiting = 0;
volatile s8 can_port_int_transmiting = 0;


CAN_MO_TypeDef *can_mo = ((CAN_MO_TypeDef *)CAN_MO0_BASE);
XMC_CAN_NODE_t *can_node_ext = ((XMC_CAN_NODE_t *)CAN_NODE1_BASE);
XMC_CAN_NODE_t *can_node_int = ((XMC_CAN_NODE_t *)CAN_NODE0_BASE);


/* CAN message */
XMC_CAN_MO_t can_ext_mo =
{
  .can_mo_ptr = CAN_MO63,
  .can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2,
  .can_identifier = 0xff,
  .can_id_mask = 0x1fffffff,
  .can_id_mode = XMC_CAN_FRAME_TYPE_STANDARD_11BITS,
  .can_ide_mask = 1,
  .can_data_length = 8,
  .can_mo_type = XMC_CAN_MO_TYPE_TRANSMSGOBJ
};

/* CAN message */
XMC_CAN_MO_t can_ext_mo_hi =
{
  .can_mo_ptr = CAN_MO61,
  .can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2,
  .can_identifier = V_Trac_PDOF_TX,
  .can_id_mask = 0x1fffffff,
  .can_id_mode = XMC_CAN_FRAME_TYPE_STANDARD_11BITS,
  .can_ide_mask = 1,
  .can_data_length = 8,
  .can_mo_type = XMC_CAN_MO_TYPE_TRANSMSGOBJ
};

XMC_CAN_MO_t can_int_mo =
{
  .can_mo_ptr = CAN_MO62,
  .can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2,
  .can_identifier = 0xff,
  .can_id_mask = 0xff,
  .can_id_mode = XMC_CAN_FRAME_TYPE_STANDARD_11BITS,
  .can_ide_mask = 1,
  .can_data_length = 8,
  .can_mo_type = XMC_CAN_MO_TYPE_TRANSMSGOBJ
};

/* CAN message */
XMC_CAN_MO_t can_int_mo_hi =
{
  .can_mo_ptr = CAN_MO60,
  .can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2,
  .can_identifier = V_Trac_PDOF_TX,
  .can_id_mask = 0x1fffffff,
  .can_id_mode = XMC_CAN_FRAME_TYPE_STANDARD_11BITS,
  .can_ide_mask = 1,
  .can_data_length = 8,
  .can_mo_type = XMC_CAN_MO_TYPE_TRANSMSGOBJ
};



/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_125K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 125000,
  .sample_point = 8000,
  .sjw = 1,
};


/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_250K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 250000,
  .sample_point = 8000,
  .sjw = 1,
};

/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_500K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 500000,
  .sample_point = 8000,
  .sjw = 1,
};

/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_1000K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 1000000,
  .sample_point = 8000,
  .sjw = 1,
};

static void init_ext_can(void);
static void init_int_can(void);

/*===========================================================================
  globale Funktionen                                                       */


//--------------------------------------------------------------
/// \brief add_to_can_list
/// Allocate message object ot a list
/// \param[in]  list_no     list no.
/// \param[in]  mailbox_no  mailbox no.
/// \return void
//--------------------------------------------------------------

void add_to_can_list(s16 list_no, s16 mailbox_no)
{
    while ((CAN->PANCTR & CAN_PANCTR_BUSY_Msk) != 0)
    {
        ;
    }
    CAN->PANCTR = ((((u32)list_no + 1U) & 7U) << 24U) | (((u32)mailbox_no & 63U) << 16U) | 2U;
    while ((CAN->PANCTR & CAN_PANCTR_BUSY_Msk) != 0)
    {
        ;
    }
}

//--------------------------------------------------------------
/// \brief set_up_interrupt_node
/// Setup transmit interrupt node pointer
/// \param[in]  mailbox_no  mailbox_no
/// \param[in]  node        no pointer
/// \return void
//--------------------------------------------------------------

void set_up_interrupt_node(s16 mailbox_no, s16 node)
{
    WR_REG(can_mo[mailbox_no].MOIPR, CAN_MO_MOIPR_TXINP_Msk, CAN_MO_MOIPR_TXINP_Pos, node);
}
//--------------------------------------------------------------
/// \brief clear_newdat
/// Reset new data
/// \param[in]  mailbox_no  mailbox_no
/// \return void
//--------------------------------------------------------------

void clear_newdat(s16 mailbox_no)
{
    can_mo[mailbox_no].MOCTR = BIT3;
}

//--------------------------------------------------------------
/// \brief can_hardware_init
/// Initialize can hardware
/// \return void
//--------------------------------------------------------------

void can_hardware_init(void)
{
    /*Configure CAN Module*/
    XMC_CAN_Init(CAN, CAN_FREQUENCY);
    init_ext_can();
    init_int_can();
}

//--------------------------------------------------------------
/// \brief can_hardware_test_tic
/// can hardware test tic
/// \return void
//--------------------------------------------------------------

void can_hardware_test_tic(void)
{
    s16 call_ret;
    can_mailbox mailbox;

    mailbox.store.u32data[0] = 0x12132242;
    mailbox.store.u32data[1] = 0x62189272;
    mailbox.dlc = 8;
    mailbox.extended = XMC_CAN_FRAME_TYPE_EXTENDED_29BITS;
    mailbox.id.full = 0x1234567;
    mailbox.port = 1;
    call_ret = send_can_message(&mailbox);
    
    mailbox.dlc = 8;
    mailbox.store.u32data[0] = 0x12345678;
    mailbox.store.u32data[1] = 0x87654321;
    mailbox.extended = XMC_CAN_FRAME_TYPE_STANDARD_11BITS;
    mailbox.id.full = 0x345;
    call_ret = send_can_message(&mailbox);
    
    mailbox.dlc = 8;
    mailbox.store.u32data[0] = 0x22334455;
    mailbox.store.u32data[1] = 0x66778899;
    mailbox.extended = XMC_CAN_FRAME_TYPE_STANDARD_11BITS;
    mailbox.id.full = 0x125;
    call_ret = send_can_message(&mailbox);
    return;
}
//--------------------------------------------------------------
/// \brief can_got_a_message
/// Check to see if a mailbox has received a message and return the mailbox no
/// \return value s16, -1 fail, otherwise mail box number
//--------------------------------------------------------------

s16 can_got_a_message(void)
{
    s16 msb_set = -1;                     /* return value if no pending messages*/

    if ((CAN->MSID[0] & 0x20) == 0)       /* nothing pending if == 32*/
    {
        msb_set = CAN->MSID[0];
        CAN->MSPND[0] &= ~(1U << (u32)msb_set);
    }
    else if ((CAN->MSID[1] & 0x20) == 0)  /* nothing pending if == 32*/
    {
        msb_set = CAN->MSID[1];
        CAN->MSPND[1] &= ~(1U << (u32)msb_set);
        msb_set += 32;                    /* Add 32, because 2nd set of 32 mailboxes*/
    }
    else
    {
        ;
    }
    return(msb_set);
}

void set_up_pending_flag(s16 mailbox_no)
{
    // Set up the pending bit for the mailbox, we sequentially allocate these in ascending order for the mailbox
    WR_REG(can_mo[mailbox_no].MOIPR, CAN_MO_MOIPR_MPN_Msk, CAN_MO_MOIPR_MPN_Pos, mailbox_no);
}


//--------------------------------------------------------------
/// \brief setup_receive_mailbox
/// Check to see if a mailbox has received a message and return the mailbox no
/// \param[in]  port              can port
/// \param[in]  mailbox_no        mailbox number
/// \param[in]  acceptance_id     acceptance id
/// \param[in]  acceptance_mask   acceptance mask
/// \param[in]  extended          extended
/// \return value s16, 0 fail,   otherwise mail box number
//--------------------------------------------------------------
static s16 setup_receive_mailbox(s8 port, s16 mailbox_no, s32 acceptance_id)
{
    s16 pd_ret;
    if (mailbox_assigned[mailbox_no] != 0)
    {  
        can_mo[mailbox_no].MOCTR   = 0x00A00000;    // load MO control register, Receive mailbox, and enable receive
        can_mo[mailbox_no].MOFCR   = 0x08010000;    // load MO function control register
        can_mo[mailbox_no].MOFGPR  = 0x00000000;    // load MO FIFO/gateway pointer register
        can_mo[mailbox_no].MOIPR   = 0x00000000;    // load MO1 interrupt pointer register
        set_up_pending_flag(mailbox_no);            // Allocate the pending bit for the mailbox, so we can recognize the recieve source
        set_up_interrupt_node(mailbox_no, port);        // All reveive message interrupts on node 0
        can_mo[mailbox_no].MOCTR   = 0x00200000;    // set MSGVAL
        can_mo[mailbox_no].MOAMR = 0x20000000U | (((CAN_11_BIT_MASK & CAN_11_BIT_MASK) << 2U ) << 16U);        // load MO acceptance mask register
        can_mo[mailbox_no].MOAR = 0x80000000 | ((((u32)acceptance_id & (u32)CAN_11_BIT_MASK) << 2 ) << 16);       // ID
        XMC_CAN_AllocateMOtoNodeList(CAN, port, mailbox_no);
        pd_ret = 1;
    }
    else
    {   
        pd_ret = 0;
    }
    return pd_ret;
}

s16 mailbox_vInit(s8 port, s32 acceptance_id)
{
    s16 mail_box = assign_a_mailbox(port);
    s16 pd_ret = -1;
    s16 call_result;
    if(mail_box > -1)
    {
        call_result = setup_receive_mailbox(port, mail_box, acceptance_id);
        pd_ret = 0;
    }
    return pd_ret;
}

void set_mailbox_assigned_flag(s16 mailbox_no)
{
    mailbox_assigned[mailbox_no] = 1;
}



//--------------------------------------------------------------
/// \brief receive_can_messages_tic
/// Receive can messages and place in the received message FIFO.
/// \param[in]  void
/// \return     void
//--------------------------------------------------------------
void receive_can_messages_tic(void)
{
    s16 mailbox_no;
    
    /*check for new messages*/
    
    while ((mailbox_no = can_got_a_message()) >= 0)
    {
        can_received_messages.mail_box[can_received_messages.in_ptr] = mailbox_no;
        can_received_messages.in_ptr++;
        if (can_received_messages.in_ptr >= MESSAGE_RECEIVED_BUFFER_SIZE)
        {      
            can_received_messages.in_ptr = 0;
        }
        
        /* mailbox_no needs to be saved with the message so it knows where it came from, for back referencing */
        can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].mailbox_no = mailbox_no;
        can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].port = can_message[mailbox_no].port;
        if ((can_mo[mailbox_no].MOAR & BIT29) != 0)                    /* check for extended id */
        {      
            can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].id.full = can_mo[mailbox_no].MOAR & CAN_29_BIT_MASK;
        }
        else
        {      
            can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].id.full = (can_mo[mailbox_no].MOAR >> 18) & CAN_11_BIT_MASK;
        }
        can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].store.u32data[0] = can_mo[mailbox_no].MODATAL;
        can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].store.u32data[1] = can_mo[mailbox_no].MODATAH;
        can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].dlc =(can_mo[mailbox_no].MOFCR >> 24) & 0x0f;
        clear_newdat(mailbox_no);
        if (++can_message[mailbox_no].buffer.in_ptr >= CAN_BUFFER_SIZE)
        {      
            can_message[mailbox_no].buffer.in_ptr = 0;
        }
    }
}

//--------------------------------------------------------------
/// \brief transmit_can_messages
/// Low level routine to tranmit the pending messages in the transmit FIFO
/// \param[in]  port which port to transmit
/// \return     void
//--------------------------------------------------------------
void transmit_can_messages_ext(void)
{
    can_mailbox* box_out = &(can_transmit_message[CAN_PORT_EXT].buffer[can_transmit_message[CAN_PORT_EXT].out_ptr]);
    can_port_ext_transmiting = 1;

    can_ext_mo.can_mo_ptr->MOAR = ((can_ext_mo.can_mo_ptr->MOAR) & 0xE0000000) | (box_out->id.full << 18) ;
    can_ext_mo.can_mo_ptr->MOFCR = ((can_ext_mo.can_mo_ptr->MOFCR ) & 0xf0ffffff) |((u32)box_out->dlc << 24);
    can_ext_mo.can_mo_ptr->MOCTR = 0x00000020;
    can_ext_mo.can_mo_ptr->MODATAL = box_out->store.u32data[0];
    can_ext_mo.can_mo_ptr->MODATAH = box_out->store.u32data[1];
    can_ext_mo.can_mo_ptr->MOCTR = 0x07280040;
}
void transmit_can_messages_int(void)
{
    can_mailbox* box_out = &(can_transmit_message[CAN_PORT_INT].buffer[can_transmit_message[CAN_PORT_INT].out_ptr]);
    can_port_int_transmiting = 1;

    can_int_mo.can_mo_ptr->MOAR = ((can_int_mo.can_mo_ptr->MOAR) & 0xE0000000) | (box_out->id.full << 18) ;
    can_int_mo.can_mo_ptr->MOFCR = ((can_int_mo.can_mo_ptr->MOFCR ) & 0xf0ffffff) |((u32)box_out->dlc << 24);
    can_int_mo.can_mo_ptr->MOCTR = 0x00000020;
    can_int_mo.can_mo_ptr->MODATAL = box_out->store.u32data[0];
    can_int_mo.can_mo_ptr->MODATAH = box_out->store.u32data[1];
    can_int_mo.can_mo_ptr->MOCTR = 0x07280040;
}

//--------------------------------------------------------------
/// \brief can_ext_transmit_interrupt
/// transmit message 
/// \param[in]  void
/// \return     void
//--------------------------------------------------------------

void can_ext_transmit_interrupt(void)
{
    can_transmit_message[CAN_PORT_EXT].out_ptr++;
    can_transmit_message[CAN_PORT_EXT].out_ptr &= NO_OF_TRANSMIT_BUFFERS - 1;
    /*Check for pending messages in the transmit FIFO*/
    if (can_transmit_message[CAN_PORT_EXT].in_ptr == can_transmit_message[CAN_PORT_EXT].out_ptr)
    {
        can_port_ext_transmiting = 0;
    }
    else
    {
        transmit_can_messages_ext();
    }
}

static void init_ext_can(void)
{
    /*Configure CAN Node baudrate*/
    XMC_CAN_NODE_NominalBitTimeConfigure(can_node_ext, &baud_500K);
    
    XMC_CAN_NODE_EnableConfigurationChange(can_node_ext);
    XMC_CAN_NODE_SetInitBit(can_node_ext);

    /*CAN.N1_RxDD*/
    XMC_GPIO_SetMode(CAN_EXT_RX_PIN, XMC_GPIO_MODE_INPUT_TRISTATE);
    /* Configure CAN NODE input pin */
    XMC_CAN_NODE_SetReceiveInput(can_node_ext, XMC_CAN_NODE_RECEIVE_INPUT_RXDCA);

    /*Message Configuration*/
    XMC_CAN_MO_Config(&can_ext_mo);
    
    /*Allocate MO in Node List*/
    XMC_CAN_AllocateMOtoNodeList(CAN, CAN_PORT_EXT, 63);

    /*Message Configuration*/
    XMC_CAN_MO_Config(&can_ext_mo_hi);
    
    /*Allocate MO in Node List*/
    XMC_CAN_AllocateMOtoNodeList(CAN, CAN_PORT_EXT, 61);

    CAN->MSIMASK = 0xffffffff;
    
    XMC_CAN_MO_EnableEvent(&can_ext_mo, XMC_CAN_MO_EVENT_TRANSMIT);
    XMC_CAN_MO_SetEventNodePointer(&can_ext_mo, XMC_CAN_MO_POINTER_EVENT_TRANSMIT, 7 );

    NVIC_SetPriority(CAN0_7_IRQn,   CAN0_7_INT_PRI);         /* Set interrupt priority*/

    /*Enable nvic node*/
    NVIC_EnableIRQ(CAN0_7_IRQn);


    XMC_CAN_NODE_DisableConfigurationChange(can_node_ext);
    XMC_CAN_NODE_ResetInitBit(can_node_ext);

    /*CAN.N1_TxD*/
    XMC_GPIO_SetMode(CAN_EXT_TX_PIN, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2);
}

static void init_int_can(void)
{
    /*Configure CAN Node baudrate*/
    XMC_CAN_NODE_NominalBitTimeConfigure(can_node_int, &baud_1000K);
    
    XMC_CAN_NODE_EnableConfigurationChange(can_node_int);
    XMC_CAN_NODE_SetInitBit(can_node_int);

    /*CAN.N1_RxDD*/
    XMC_GPIO_SetMode(CAN_INT_RX_PIN, XMC_GPIO_MODE_INPUT_TRISTATE);
    /* Configure CAN NODE input pin */
    XMC_CAN_NODE_SetReceiveInput(can_node_int, XMC_CAN_NODE_RECEIVE_INPUT_RXDCA);

    /*Message Configuration*/
    XMC_CAN_MO_Config(&can_int_mo);
    
    /*Allocate MO in Node List*/
    XMC_CAN_AllocateMOtoNodeList(CAN, CAN_PORT_INT, 62);

    /*Message Configuration*/
    XMC_CAN_MO_Config(&can_int_mo_hi);
    
    /*Allocate MO in Node List*/
    XMC_CAN_AllocateMOtoNodeList(CAN, CAN_PORT_INT, 60);

    CAN->MSIMASK = 0xffffffff;
    
    XMC_CAN_MO_EnableEvent(&can_int_mo, XMC_CAN_MO_EVENT_TRANSMIT);
    XMC_CAN_MO_SetEventNodePointer(&can_int_mo, XMC_CAN_MO_POINTER_EVENT_TRANSMIT, 6);

    NVIC_SetPriority(CAN0_6_IRQn,   CAN0_6_INT_PRI);         /* Set interrupt priority*/

    /*Enable nvic node*/
    NVIC_EnableIRQ(CAN0_6_IRQn);


    XMC_CAN_NODE_DisableConfigurationChange(can_node_int);
    XMC_CAN_NODE_ResetInitBit(can_node_int);

    /*CAN.N1_TxD*/
    XMC_GPIO_SetMode(CAN_INT_TX_PIN, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2);
}
void can_int_transmit_interrupt(void)
{
    can_transmit_message[CAN_PORT_INT].out_ptr++;
    can_transmit_message[CAN_PORT_INT].out_ptr &= NO_OF_TRANSMIT_BUFFERS - 1;
    /*Check for pending messages in the transmit FIFO*/
    if (can_transmit_message[CAN_PORT_INT].in_ptr == can_transmit_message[CAN_PORT_INT].out_ptr)
    {
        can_port_int_transmiting = 0;
    }
    else
    {
        transmit_can_messages_int();
    }
}


